﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using HJ212_Common;
using SailHero.Soft.ESB.Communication;
using SailHero.Soft.ESB.Communication.ClientAndServer.Communication;

namespace HJ212_Protocol
{
    public class Message
    {
        private string _head = "##";
        public byte[] Content { get; set; }
        public string From { get; set; }
        public string To { get; set; }
        public string MN { get; set; }
        public string PW { get; set; }
        public string QN { get; set; }
        public string Flag { get; set; }
        public string ST { get; set; }
        public string CP { get; set; }
        public string CN { get; set; }
        public int MsgType { get; set; }
        public string CRC { get; set; }

        public int Size { get; set; }

        public string Head
        {
            get { return _head; }
            set { _head = value; }
        }

        public Message()
        {

        }

        public byte[] ToBytes()
        {
            byte[] _byte;
            using (MemoryStream mem = new MemoryStream())
            {
                BinaryWriter writer = new BinaryWriter(mem);
                writer.Write(System.Text.Encoding.ASCII.GetBytes(_head));
                writer.Write(System.Text.Encoding.ASCII.GetBytes(Size.ToString("000#")));
                if (Size > 0)
                {
                    writer.Write(Content);
                }
                string crcX = new CRC16().CRC16_T212(Encoding.ASCII.GetString(Content));
                writer.Write(System.Text.Encoding.ASCII.GetBytes(crcX.PadLeft(4, '0')));//CRC校验的十六进制整数
                //writer.Write(_crc);
                writer.Write(Encoding.ASCII.GetBytes(new char[] { (char)13 }));//回车符
                writer.Write(Encoding.ASCII.GetBytes(new char[] { (char)10 }));//换行符
                //writer.Write(System.Text.Encoding.Unicode.GetBytes(StringPad(From, 60, ' ', 1)));
                //writer.Write(System.Text.Encoding.Unicode.GetBytes(StringPad(To, 60, ' ', 1)));
                _byte = mem.ToArray();
                writer.Close();
            }
            return _byte;
        }


        public static Message FromBytes(byte[] Buffer)
        {
            Message message = new Message();
            using (MemoryStream mem = new MemoryStream(Buffer))
            {
                BinaryReader reader = new BinaryReader(mem);

                var head = reader.ReadBytes(2);
                string strHead = System.Text.Encoding.ASCII.GetString(head);
                message._head = strHead;
                message.Size = Convert.ToInt32(System.Text.Encoding.ASCII.GetString(reader.ReadBytes(4)));
                if (message.Size > 0)
                {
                    message.Content = reader.ReadBytes(message.Size);
                }
                message.CRC = System.Text.Encoding.ASCII.GetString(reader.ReadBytes(4));

                #region CRC强制校验
                string IsCRCCheck = ConfigOprater.GetNodeValue("IsCRCCheck");
                if (IsCRCCheck == "1")
                {
                    string crcX = new CRC16().CRC16_T212(Encoding.ASCII.GetString(message.Content));
                    ; //16进制CRC校验码


                    if (crcX.PadLeft(4, '0') != message.CRC)
                    {
                        throw new CommunicationException(
                            @"由于CRC校验出错，故消息接收超时！
                                                        消息内容为：" +
                            Encoding.ASCII.GetString(message.Content) +
                            "消息中crc：" + message.CRC +
                            "按协议计算的crc：" + crcX.PadLeft(4, '0')
                            );
                    }
                } 
                #endregion

                var dd = reader.ReadBytes(2);
                string mct = System.Text.Encoding.ASCII.GetString(message.Content);
                int mtype = 0;
                string mn = "", pw = "", cn = "", cp = "", flag = "", st = "", qn = "";
                GetSplitContent(mct, out  mn, out  pw, out  cn, out cp, out  flag, out  st, out  qn, out mtype);
                message.QN = qn;
                message.CN = cn;
                message.CP = cp;
                message.Flag = flag;
                message.ST = st;
                message.MsgType = mtype;
                message.MN = mn;
                message.PW = pw;///todo:根据qn检索出相应的MessageID
                reader.Close();
            }
            return message;
        }
        /// <summary>
        /// 从指令信息中获通话的唯一标识QN,MN,PW
        /// </summary>
        /// <param name="msgContent">指令信息内容</param>
        /// <param name="MN">MN号</param>
        /// <param name="PW">密码</param>
        /// <param name="MsgType">指令信息类型 0 是上位机的初次请求，1 是现场机的应答或上传</param>
        /// <returns></returns>
        public static void GetSplitContent(string msgContent, out string MN, out string PW, out string CN, out string CP, out string Flag, out string ST, out string QN, out int MsgType)
        {
            MsgType = 0;
            MN = null;
            PW = null;
            CN = null;
            CP = null;
            Flag = null;
            ST = null;
            QN = null;
            try
            {
                if (string.IsNullOrEmpty(msgContent.Trim()))
                {
                    return;
                }
                string[] strsContent = msgContent.Split(';');
                foreach (string s in strsContent)
                {
                    string c = s.ToUpper().Replace(" ", "").Replace("　", "");//清除全半角空格，保证兼容性
                    string[] strs = c.Split('=');
                    switch (strs[0])
                    {
                        case "QN":
                            QN = strs[1];
                            break;
                        case "MN":
                            MN = strs[1];
                            break;
                        case "CN":
                            CN = strs[1];
                            break;
                        case "CP":
                            int s_Start = msgContent.IndexOf("&&");
                            int s_end = msgContent.LastIndexOf("&&");
                            CP = msgContent.Substring(s_Start + 2, s_end - s_Start - 2);
                            break;
                        case "ST":
                            ST = strs[1];
                            break;
                        case "FLAG":
                            Flag = strs[1];
                            break;
                        case "PW":
                            PW = strs[1];
                            break;
                    }
                }

                //为了较好的兼容性，即便是QN与=间有空格也可取出相应的QN号
                string content = msgContent.ToUpper().Replace(" ", "").Replace("　", "");
                int j = content.IndexOf("ST=");
                { MsgType = 0; }
                if (j == 0)
                {
                    MsgType = 1;
                }
                if (QN == null)
                {
                    int k = content.IndexOf("QN=");

                    if (k >= 0 && content.Length >= k + 20)
                    {
                        QN = content.Substring(k + 3, 17);
                    }
                }
            }
            catch (Exception ex)
            {

                throw;
            }
            return;
        }
        /// <summary>
        /// 字符串补齐定长的函数
        /// </summary>
        /// <param name="SourceString">目标字符串</param>
        /// <param name="TargetLength">目标长度</param>
        /// <param name="PadChar">要补齐的字符</param>
        /// <param name="leftOrRight">左补齐还是右补齐 0 为左补齐</param>
        /// <returns></returns>
        public string StringPad(string SourceString, int TargetLength, char PadChar, int leftOrRight)
        {
            string functionReturnValue = null;
            dynamic SourceLength = null;
            SourceLength = SourceString.Length;
            if ((SourceLength > TargetLength))
            {
                functionReturnValue = SourceString.Substring(0, TargetLength);
            }
            if ((leftOrRight == 0))
            {
                functionReturnValue = SourceString.PadLeft(TargetLength, PadChar);
            }
            else
            {
                functionReturnValue = SourceString.PadRight(TargetLength, PadChar);
            }

            return functionReturnValue;
        }

    }
}
